package com.loklok.code.confuse.service;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiClass;
import com.loklok.code.confuse.dto.GenerateCodeDto;
import com.loklok.code.confuse.model.ClassMetaData;
import com.loklok.code.confuse.model.CodePathConfig;
import com.loklok.code.confuse.model.FeignInterfaceInfo;
import com.loklok.code.confuse.util.CommonUtil;
import com.loklok.code.confuse.util.LocalFileUtils;
import com.loklok.code.confuse.util.PsiFileUtils;
import com.loklok.code.confuse.util.VelocityUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class UrlGenerateCodeService {

    public static void fillFeignInterfaceInfos(String methodPath, Map<String, FeignInterfaceInfo> feignInterfaceInfoMap, Set<String> notMatch, List<FeignInterfaceInfo> all) {
        Set<String> inputPaths = Arrays.stream(methodPath.split("[,\n]")) // 使用正则表达式分割逗号和换行
                .map(item -> {
                    String path = item.trim();
                    return path.startsWith("/") ? path : "/" + path;
                }).filter(path -> !path.isEmpty()).collect(Collectors.toSet());



        inputPaths.stream().forEach(path -> {
            FeignInterfaceInfo feignInterfaceInfo = feignInterfaceInfoMap.get(path);
            if (feignInterfaceInfo == null) {
                notMatch.add(path);
            } else {
                all.add(feignInterfaceInfo);
            }
        });
    }

    public static void doPreGenerateCode(AnActionEvent anActionEvent, CodePathConfig config, String pckName, List<FeignInterfaceInfo> all, boolean needController) {
        if (CollectionUtils.isEmpty(all)) {
            return;
        }

        Project project = anActionEvent.getProject();
        List<ClassMetaData> classMetaDataList = FullUpdateTemplateService.getClassMetaData(all, project, needController, config.getNotCollectClass());

        int total = classMetaDataList.size();
        AtomicInteger processed = new AtomicInteger(0);

        ProgressManager.getInstance().run(new Task.Backgroundable(project, "生成代码中...", true) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                indicator.setIndeterminate(false);
                indicator.setFraction(0.0);

                // 初始化进度条信息
                AtomicInteger currentProgress = new AtomicInteger(0);
                indicator.setText("正在生成代码... (0/" + total + ")");

                // 启动异步任务
                classMetaDataList.stream()
                        .forEach(item -> doGenerateCodeAsync(anActionEvent, config, pckName, item, indicator, processed, total));

                try {
                    // 等待所有任务完成
                    while (processed.get() < total && !indicator.isCanceled()) {
                        Thread.sleep(500); // 每隔 500ms 检查一次
                        int current = processed.get();
                        double fraction = (double) current / total;
                        int currentVal = currentProgress.getAndSet(current);
                        if (currentVal != current) {
                            ApplicationManager.getApplication().invokeLater(() -> {
                                indicator.setFraction(fraction);
                                indicator.setText("正在生成代码... (" + current + "/" + total + ")");
                            });
                        }
                    }

                    // 最终更新
                    ApplicationManager.getApplication().invokeLater(() -> {
                        if (!indicator.isCanceled()) {
                            indicator.setFraction(1.0);
                            indicator.setText("代码生成完成 (" + total + "/" + total + ")");
                            Messages.showInfoMessage(project, "代码生成完成", "成功");
                        } else {
                            Messages.showInfoMessage(project, "代码生成已取消", "提示");
                        }
                        LocalFileUtils.resetApplyToAll(project);
                    });
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    ApplicationManager.getApplication().invokeLater(() ->
                            Messages.showMessageDialog(project, "任务被中断", "错误", Messages.getErrorIcon()));
                }
            }
        });
    }

    private static CompletableFuture<Void> doGenerateCodeAsync(AnActionEvent anActionEvent, CodePathConfig config, String inputPckName, ClassMetaData item, ProgressIndicator indicator, AtomicInteger processed, int total) {
        return CompletableFuture.runAsync(() -> {
            try {
                // 检查文件是否存在
                if (LocalFileUtils.isFileExist(anActionEvent.getProject(), config, item, inputPckName)) {
                    System.out.println("code file exists :" +  item.getFullClassName());

                    if(item.controllerType()){

                        File targetFile = getLocalTemplateFile(config, item, "Methods", ".vm");
                        if(!targetFile.exists()){
                            ApplicationManager.getApplication().invokeLater(() ->
                                    Messages.showErrorDialog("VM 模板：" + targetFile.getAbsolutePath() + " , 不存在", "错误"));
                        }

                        // 如果是控制器 则动态添加代码方法
                        String path = CommonUtil.pathJoint(config.getObtainRelativePath(item), inputPckName);
                        String fullPackage = CommonUtil.pathToDeclarePackage(path);
                        PsiClass psiClass = PsiFileUtils.getPsiClassByPackageAndName(anActionEvent.getProject(), fullPackage, CommonUtil.pckToClassPrefix(inputPckName) + item.getClassName());

                        if (psiClass != null) {
                            String methodText = VelocityUtils.getMethodText(targetFile.getParentFile().getAbsolutePath(), inputPckName, item.getMethodNames());

                            // 验证 methodText 是否有效
                            if (StringUtils.isNotBlank(methodText)) {
                                LocalFileUtils.addMethodToClass(anActionEvent.getProject(), psiClass, methodText);
                            } else {
                                System.err.println("Invalid method text generated: " + methodText);
                            }
                        } else {
                            System.err.println("Could not find PsiClass for: " + fullPackage + "." + CommonUtil.pckToClassPrefix(inputPckName) + item.getClassName());
                        }
                    }

                    updateIndicator(processed, total, indicator);
                    return;
                }

                List<GenerateCodeDto> result = doGenerateCode(config, inputPckName, item);

                ApplicationManager.getApplication().invokeLater(() -> {
                    result.forEach(dto -> {
                        if (dto.isCreateFile()) {
                            LocalFileUtils.writeFile(anActionEvent, dto.getFullPck(), dto.getClassName(), dto.getGenerateCode(), dto.getFileType());
                        }
                    });

                    updateIndicator(processed, total, indicator);
                });
            } catch (Exception e) {
                ApplicationManager.getApplication().invokeLater(() ->
                        Messages.showMessageDialog("生成代码失败: " + e.getMessage(), "错误", Messages.getErrorIcon()));
            }
        }, FullUpdateTemplateService.EXECUTOR);
    }


    private static void updateIndicator(AtomicInteger processed, int total, ProgressIndicator indicator) {
        int current = processed.incrementAndGet();
        double fraction = (double) current / total;
        ApplicationManager.getApplication().invokeLater(() -> {
            indicator.setFraction(fraction);
            indicator.setText("正在生成代码... (" + current + "/" + total + ")");
        });
    }


    private static List<GenerateCodeDto> doGenerateCode(CodePathConfig config,  String inputPckName, ClassMetaData item) {

        String className = item.getClassName();
        List<GenerateCodeDto> all = new ArrayList<>();

        File targetFile = getLocalTemplateFile(config, item, className, ".java.vm");

        if (!targetFile.exists()) {
            ApplicationManager.getApplication().invokeLater(() ->
                    Messages.showErrorDialog("VM 模板：" + targetFile.getAbsolutePath() + " , 不存在", "错误"));
            return all;
        }

        // 模板文件存在 通过模板文件生成 代码
        if(item.voType() || item.requestType()){
            GenerateCodeDto generateCodeDto = VelocityUtils.generateDtoVoCode(config, targetFile.getAbsolutePath(), inputPckName, item.voType());
            all.add(generateCodeDto);
        } else {
            // 控制器 生成
            GenerateCodeDto generateCodeDto = VelocityUtils.generateControllerCode(config, inputPckName, targetFile.getAbsolutePath(), item.getMethodNames());
            all.add(generateCodeDto);
        }
        return all;
    }

    @NotNull
    private static File getLocalTemplateFile(CodePathConfig config, ClassMetaData item, String className, String suffix) {
        String partPckName = item.getPartPckName();

        String templatePath = CommonUtil.pathJoint(config.getCodeTemplate(), partPckName, item.getFeignClientName());
        File targetFile = new File(templatePath, className + suffix);
        return targetFile;
    }

}
